package eu.orangeflash.webapis.xmlrpc.utils
{
	import eu.orangeflash.webapis.xmlrpc.*;
	
	public final class Deserialize
	{
		public static const ARRAY:String  = "Array";
		public static const BASE64:String = "base64";
		public static const BOOL:String   = "Boolean";
		public static const DATE:String   = "Date";
		public static const NUMBER:String = "Number";
		public static const INT:String    = "int";
		public static const STRING:String = "String";
		public static const OBJECT:String = "Object";
		public static const NULL:String	  = "null";
		
		
		/**
		 * Method, parses raw xml data to MethodResponse
		 * 
		 * @param	xml		XML, raw xml data
		 * 
		 * @return			IMethodResponse implentation
		 */
		public static function createResponse(xml:XML):IMethodResponse
		{
			var result:IMethodResponse = new MethodResponse();
			
			if(xml.children().name() == "params")
			{
				trace("success");
				var params:XMLList = xml.params.param.value;
				result.isFault = false;
				
				for each(var param:XML in params)
				{
					result.params.push(createType(XMLList(param)));
				}				
			}else
			{
				trace("fault");
				result.isFault = true;
				var fObj:Object = createType(xml.fault.value);
				result.fault.faultCode 	 = fObj.faultCode;
				result.fault.faultString = fObj.faultString;
			}
			
			return result;
		}
		
		
		private static function getComplexType(value:XMLList):String
		{
			//trace("getComplexType");
			var type:String = value.children().name();
			var result:String;
			
			switch(type)
			{				
				case "dateTime.iso8601":
					result = DATE;
					break;
				
				case "array":
					result = ARRAY;
					break;
				
				case "struct":
					result = OBJECT;
					break;
					
				default:
					result = "";				
			}
			
			return result;
		}
		
		private static function createType(value:XMLList):Object
		{
			//trace("createType");
			var result:Object;
			var type:String = getComplexType(value);
			
			if(type == "")
			{
				result = createSimple(value);
			}else if(type == OBJECT)
			{
				result = createObject(value);
			}else if(type == ARRAY)
			{
				result = createArray(value);
			}else
			{
				result = createDate(value);
			}
			
			return result;
		}
		
		private static function createArray(value:XMLList):Array
		{
			//trace("createArray");
			var result:Array = new Array();
			var v:XMLList = value.array.data.value;

			for each(var item:XML in v)
			{
				result.push(createType(XMLList(item)));
			}
			return result;
		}
		
		private static function createObject(value:XMLList):Object
		{
			//trace("createObject");
			var result:Object = new Object();
			var v:XMLList = value.struct;

			for each(var item:XML in v.member)
			{
				result[item.name.toString()] = createType(item.value)
			}
			
			
			return result;
		}
		
		private static function createSimple(value:XMLList):Object
		{
			//trace("createSimple");
			var v:XMLList = value.children();
			var type:String = v.name();
			var result:Object;
			
			switch(type)
			{
				case "string":
					result = v.toString();
					break;
				
				case "double":
					result = Number(v.toString());
					break;
				
				case "int":
					result = int(v.toString());
					break;
				
				case "i4":
					result = int(v.toString());
					break;
				
				case "boolean":
					result = Boolean(v.toString());
					break;
				
				case "base64":
					result = v.toString();
					break;		
			}
			
			return result;
		}
		
		private static function createDate(value:XMLList):Date
		{
			var rawDate:String = value.children().toString();
			
			var tempDate:Array = rawDate.split("T");
			
			var date:String    = tempDate[0];
			var time:String    = tempDate[1];
			
			var tempTime:Array = time.split(":");
			
			return new Date(Number(date.slice(0,4))		//Year
							,Number(date.slice(4,6))-1	//Month
							,Number(date.slice(6,8))	//Day
							,Number(tempTime[0])		//Hours
							,Number(tempTime[1])		//Minutes
							,Number(tempTime[2]) 		//Seconds
							);
		}
	}
}